package com.lifeverse.service;

import com.lifeverse.entity.Decision;
import com.lifeverse.entity.LifeEntity;
import com.lifeverse.entity.Resource;
import com.lifeverse.entity.ResourceAllocation;
import com.lifeverse.entity.enums.ResourceStatus;
import com.lifeverse.entity.enums.ResourceType;
import com.lifeverse.repository.ResourceAllocationRepository;
import com.lifeverse.repository.ResourceRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 资源分配器
 * 负责智能分配系统资源
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ResourceAllocator {
    
    private final ResourceRepository resourceRepository;
    private final ResourceAllocationRepository allocationRepository;
    
    /**
     * 分配资源
     */
    @Transactional
    public ResourceAllocationResult allocateResource(ResourceAllocationRequest request) {
        log.info("开始分配资源 - 类型: {}, 数量: {}, 申请者: {}", 
                request.getResourceType(), request.getRequiredAmount(), request.getRequester().getName());
        
        try {
            // 1. 查找可用资源
            List<Resource> availableResources = findAvailableResources(request);
            
            if (availableResources.isEmpty()) {
                return ResourceAllocationResult.failed("没有找到可用的资源");
            }
            
            // 2. 选择最佳资源
            Resource selectedResource = selectBestResource(availableResources, request);
            
            // 3. 执行分配
            ResourceAllocation allocation = performAllocation(selectedResource, request);
            
            log.info("资源分配成功 - 资源: {}, 分配量: {}, 分配ID: {}", 
                    selectedResource.getName(), request.getRequiredAmount(), allocation.getId());
            
            return ResourceAllocationResult.success(allocation);
            
        } catch (Exception e) {
            log.error("资源分配失败", e);
            return ResourceAllocationResult.failed("资源分配失败: " + e.getMessage());
        }
    }
    
    /**
     * 批量分配资源
     */
    @Transactional
    public List<ResourceAllocationResult> allocateResources(List<ResourceAllocationRequest> requests) {
        log.info("开始批量分配资源 - 请求数量: {}", requests.size());
        
        List<ResourceAllocationResult> results = new ArrayList<>();
        
        // 按优先级排序请求
        List<ResourceAllocationRequest> sortedRequests = requests.stream()
                .sorted((r1, r2) -> Integer.compare(r2.getPriority(), r1.getPriority()))
                .collect(Collectors.toList());
        
        for (ResourceAllocationRequest request : sortedRequests) {
            ResourceAllocationResult result = allocateResource(request);
            results.add(result);
            
            // 如果是关键资源分配失败，可能需要停止后续分配
            if (!result.isSuccess() && request.getPriority() >= 8) {
                log.warn("关键资源分配失败，停止后续分配 - 资源类型: {}", request.getResourceType());
                break;
            }
        }
        
        log.info("批量资源分配完成 - 成功: {}, 失败: {}", 
                results.stream().mapToInt(r -> r.isSuccess() ? 1 : 0).sum(),
                results.stream().mapToInt(r -> r.isSuccess() ? 0 : 1).sum());
        
        return results;
    }
    
    /**
     * 释放资源
     */
    @Transactional
    public boolean releaseResource(Long allocationId, BigDecimal releaseAmount) {
        log.info("释放资源 - 分配ID: {}, 释放量: {}", allocationId, releaseAmount);
        
        try {
            ResourceAllocation allocation = allocationRepository.findById(allocationId)
                    .orElseThrow(() -> new RuntimeException("分配记录不存在: " + allocationId));
            
            if (!allocation.isActive()) {
                log.warn("分配记录不是活跃状态 - ID: {}, 状态: {}", allocationId, allocation.getAllocationStatus());
                return false;
            }
            
            Resource resource = allocation.getResource();
            BigDecimal actualReleaseAmount = releaseAmount != null ? releaseAmount : allocation.getAllocatedAmount();
            
            // 释放资源
            boolean released = resource.release(actualReleaseAmount);
            if (!released) {
                log.error("资源释放失败 - 资源: {}, 释放量: {}", resource.getName(), actualReleaseAmount);
                return false;
            }
            
            // 更新分配记录
            allocation.endUsing();
            allocationRepository.save(allocation);
            resourceRepository.save(resource);
            
            log.info("资源释放成功 - 资源: {}, 释放量: {}", resource.getName(), actualReleaseAmount);
            return true;
            
        } catch (Exception e) {
            log.error("资源释放失败 - 分配ID: {}", allocationId, e);
            return false;
        }
    }
    
    /**
     * 优化资源分配
     */
    @Transactional
    public ResourceOptimizationResult optimizeResourceAllocation(ResourceOptimizationRequest request) {
        log.info("开始优化资源分配 - 目标: {}", request.getOptimizationGoal());
        
        try {
            List<ResourceAllocation> activeAllocations = allocationRepository.findActiveAllocations(
                    Arrays.asList("ACTIVE", "IN_USE"));
            
            ResourceOptimizationResult result = new ResourceOptimizationResult();
            result.setOptimizationGoal(request.getOptimizationGoal());
            result.setOriginalAllocations(activeAllocations.size());
            
            switch (request.getOptimizationGoal()) {
                case COST_OPTIMIZATION:
                    result = optimizeForCost(activeAllocations, request);
                    break;
                case PERFORMANCE_OPTIMIZATION:
                    result = optimizeForPerformance(activeAllocations, request);
                    break;
                case UTILIZATION_OPTIMIZATION:
                    result = optimizeForUtilization(activeAllocations, request);
                    break;
                case BALANCED_OPTIMIZATION:
                    result = optimizeForBalance(activeAllocations, request);
                    break;
                default:
                    result.setSuccess(false);
                    result.setMessage("不支持的优化目标: " + request.getOptimizationGoal());
            }
            
            log.info("资源分配优化完成 - 目标: {}, 结果: {}", 
                    request.getOptimizationGoal(), result.isSuccess() ? "成功" : "失败");
            
            return result;
            
        } catch (Exception e) {
            log.error("资源分配优化失败", e);
            ResourceOptimizationResult result = new ResourceOptimizationResult();
            result.setSuccess(false);
            result.setMessage("优化失败: " + e.getMessage());
            return result;
        }
    }
    
    /**
     * 查找可用资源
     */
    private List<Resource> findAvailableResources(ResourceAllocationRequest request) {
        List<ResourceStatus> availableStatuses = Arrays.asList(ResourceStatus.AVAILABLE, ResourceStatus.RECYCLED);
        
        List<Resource> resources = resourceRepository.findResourcesWithSufficientCapacityByType(
                request.getResourceType(), request.getRequiredAmount(), availableStatuses);
        
        // 按位置过滤
        if (request.getPreferredLocation() != null) {
            resources = resources.stream()
                    .filter(r -> request.getPreferredLocation().equals(r.getLocation()))
                    .collect(Collectors.toList());
        }
        
        // 按标签过滤
        if (request.getRequiredTags() != null && !request.getRequiredTags().isEmpty()) {
            resources = resources.stream()
                    .filter(r -> hasRequiredTags(r, request.getRequiredTags()))
                    .collect(Collectors.toList());
        }
        
        return resources;
    }
    
    /**
     * 选择最佳资源
     */
    private Resource selectBestResource(List<Resource> availableResources, ResourceAllocationRequest request) {
        return availableResources.stream()
                .max(Comparator.comparing((Resource r) -> calculateResourceScore(r, request)))
                .orElse(availableResources.get(0));
    }
    
    /**
     * 计算资源评分
     */
    private double calculateResourceScore(Resource resource, ResourceAllocationRequest request) {
        double score = 0.0;
        
        // 优先级权重
        score += resource.getPriority() * 10;
        
        // 容量匹配度
        double capacityMatch = request.getRequiredAmount().doubleValue() / resource.getAvailableAmount().doubleValue();
        score += (1.0 - Math.abs(capacityMatch - 0.5)) * 20; // 偏好使用50%容量
        
        // 成本效益
        if (resource.getUnitCost() != null) {
            score += (100.0 / resource.getUnitCost().doubleValue()) * 15;
        }
        
        // 位置匹配
        if (request.getPreferredLocation() != null && 
            request.getPreferredLocation().equals(resource.getLocation())) {
            score += 25;
        }
        
        // 使用历史
        if (resource.getLastUsedAt() != null) {
            long daysSinceLastUse = java.time.temporal.ChronoUnit.DAYS.between(
                    resource.getLastUsedAt(), LocalDateTime.now());
            score += Math.max(0, 10 - daysSinceLastUse); // 最近使用的资源得分更高
        }
        
        return score;
    }
    
    /**
     * 执行资源分配
     */
    private ResourceAllocation performAllocation(Resource resource, ResourceAllocationRequest request) {
        // 分配资源
        boolean allocated = resource.allocate(request.getRequiredAmount(), request.getRequester());
        if (!allocated) {
            throw new RuntimeException("资源分配失败");
        }
        
        // 创建分配记录
        ResourceAllocation allocation = new ResourceAllocation();
        allocation.setResource(resource);
        allocation.setAllocatedTo(request.getRequester());
        allocation.setDecision(request.getDecision());
        allocation.setAllocatedAmount(request.getRequiredAmount());
        allocation.setAllocationReason(request.getReason());
        allocation.setPriority(request.getPriority());
        allocation.setPlannedReleaseAt(request.getPlannedReleaseAt());
        
        if (request.isStartImmediately()) {
            allocation.startUsing();
        }
        
        // 计算分配成本
        if (resource.getUnitCost() != null) {
            BigDecimal cost = resource.getUnitCost().multiply(request.getRequiredAmount());
            allocation.setAllocationCost(cost);
        }
        
        // 保存记录
        resourceRepository.save(resource);
        return allocationRepository.save(allocation);
    }
    
    /**
     * 检查是否有必需的标签
     */
    private boolean hasRequiredTags(Resource resource, List<String> requiredTags) {
        if (resource.getTags() == null) {
            return false;
        }
        
        String[] resourceTags = resource.getTags().split(",");
        Set<String> resourceTagSet = Arrays.stream(resourceTags)
                .map(String::trim)
                .collect(Collectors.toSet());
        
        return resourceTagSet.containsAll(requiredTags);
    }
    
    /**
     * 成本优化
     */
    private ResourceOptimizationResult optimizeForCost(List<ResourceAllocation> allocations, 
                                                     ResourceOptimizationRequest request) {
        ResourceOptimizationResult result = new ResourceOptimizationResult();
        result.setOptimizationGoal(request.getOptimizationGoal());
        
        // 找出成本最高的分配
        List<ResourceAllocation> highCostAllocations = allocations.stream()
                .filter(a -> a.getAllocationCost() != null)
                .sorted((a1, a2) -> a2.getAllocationCost().compareTo(a1.getAllocationCost()))
                .limit(10)
                .collect(Collectors.toList());
        
        int optimizedCount = 0;
        BigDecimal totalSavings = BigDecimal.ZERO;
        
        for (ResourceAllocation allocation : highCostAllocations) {
            // 尝试找到更便宜的替代资源
            List<Resource> cheaperAlternatives = findCheaperAlternatives(allocation);
            
            if (!cheaperAlternatives.isEmpty()) {
                Resource cheaperResource = cheaperAlternatives.get(0);
                BigDecimal savings = calculateCostSavings(allocation, cheaperResource);
                
                if (savings.compareTo(BigDecimal.ZERO) > 0) {
                    // 执行资源迁移（简化实现）
                    optimizedCount++;
                    totalSavings = totalSavings.add(savings);
                }
            }
        }
        
        result.setSuccess(true);
        result.setOptimizedAllocations(optimizedCount);
        result.setCostSavings(totalSavings);
        result.setMessage(String.format("成本优化完成，优化了%d个分配，节省成本%.2f", 
                                       optimizedCount, totalSavings.doubleValue()));
        
        return result;
    }
    
    /**
     * 性能优化
     */
    private ResourceOptimizationResult optimizeForPerformance(List<ResourceAllocation> allocations, 
                                                            ResourceOptimizationRequest request) {
        ResourceOptimizationResult result = new ResourceOptimizationResult();
        result.setOptimizationGoal(request.getOptimizationGoal());
        
        // 找出低效率的分配
        List<ResourceAllocation> lowEfficiencyAllocations = allocations.stream()
                .filter(a -> a.getEfficiencyScore() != null && 
                           a.getEfficiencyScore().compareTo(BigDecimal.valueOf(60)) < 0)
                .collect(Collectors.toList());
        
        int optimizedCount = 0;
        
        for (ResourceAllocation allocation : lowEfficiencyAllocations) {
            // 尝试找到性能更好的资源
            List<Resource> betterResources = findBetterPerformanceResources(allocation);
            
            if (!betterResources.isEmpty()) {
                // 执行资源迁移（简化实现）
                optimizedCount++;
            }
        }
        
        result.setSuccess(true);
        result.setOptimizedAllocations(optimizedCount);
        result.setMessage(String.format("性能优化完成，优化了%d个分配", optimizedCount));
        
        return result;
    }
    
    /**
     * 利用率优化
     */
    private ResourceOptimizationResult optimizeForUtilization(List<ResourceAllocation> allocations, 
                                                            ResourceOptimizationRequest request) {
        ResourceOptimizationResult result = new ResourceOptimizationResult();
        result.setOptimizationGoal(request.getOptimizationGoal());
        
        // 找出低利用率的分配
        List<ResourceAllocation> lowUtilizationAllocations = allocations.stream()
                .filter(a -> a.getUsageRate().compareTo(BigDecimal.valueOf(0.3)) < 0)
                .collect(Collectors.toList());
        
        int optimizedCount = 0;
        
        for (ResourceAllocation allocation : lowUtilizationAllocations) {
            // 尝试合并或调整分配
            if (canOptimizeUtilization(allocation)) {
                optimizedCount++;
            }
        }
        
        result.setSuccess(true);
        result.setOptimizedAllocations(optimizedCount);
        result.setMessage(String.format("利用率优化完成，优化了%d个分配", optimizedCount));
        
        return result;
    }
    
    /**
     * 平衡优化
     */
    private ResourceOptimizationResult optimizeForBalance(List<ResourceAllocation> allocations, 
                                                        ResourceOptimizationRequest request) {
        ResourceOptimizationResult result = new ResourceOptimizationResult();
        result.setOptimizationGoal(request.getOptimizationGoal());
        
        // 综合考虑成本、性能和利用率
        int totalOptimized = 0;
        
        // 执行轻量级的成本优化
        ResourceOptimizationResult costResult = optimizeForCost(allocations, request);
        totalOptimized += costResult.getOptimizedAllocations();
        
        // 执行轻量级的性能优化
        ResourceOptimizationResult performanceResult = optimizeForPerformance(allocations, request);
        totalOptimized += performanceResult.getOptimizedAllocations();
        
        // 执行轻量级的利用率优化
        ResourceOptimizationResult utilizationResult = optimizeForUtilization(allocations, request);
        totalOptimized += utilizationResult.getOptimizedAllocations();
        
        result.setSuccess(true);
        result.setOptimizedAllocations(totalOptimized);
        result.setCostSavings(costResult.getCostSavings());
        result.setMessage(String.format("平衡优化完成，总共优化了%d个分配", totalOptimized));
        
        return result;
    }
    
    /**
     * 查找更便宜的替代资源
     */
    private List<Resource> findCheaperAlternatives(ResourceAllocation allocation) {
        List<ResourceStatus> availableStatuses = Arrays.asList(ResourceStatus.AVAILABLE, ResourceStatus.RECYCLED);
        
        return resourceRepository.findCheaperResourcesByType(
                allocation.getResource().getType(), 
                availableStatuses, 
                PageRequest.of(0, 5));
    }
    
    /**
     * 查找性能更好的资源
     */
    private List<Resource> findBetterPerformanceResources(ResourceAllocation allocation) {
        List<ResourceStatus> availableStatuses = Arrays.asList(ResourceStatus.AVAILABLE, ResourceStatus.RECYCLED);
        
        return resourceRepository.findBestPerformanceResourcesByType(
                allocation.getResource().getType(), 
                availableStatuses, 
                PageRequest.of(0, 5));
    }
    
    /**
     * 计算成本节省
     */
    private BigDecimal calculateCostSavings(ResourceAllocation allocation, Resource cheaperResource) {
        if (allocation.getAllocationCost() == null || cheaperResource.getUnitCost() == null) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal newCost = cheaperResource.getUnitCost().multiply(allocation.getAllocatedAmount());
        return allocation.getAllocationCost().subtract(newCost);
    }
    
    /**
     * 判断是否可以优化利用率
     */
    private boolean canOptimizeUtilization(ResourceAllocation allocation) {
        // 简化实现：检查是否可以减少分配量
        return allocation.getUsageRate().compareTo(BigDecimal.valueOf(0.5)) < 0;
    }
    
    // 内部类定义
    public static class ResourceAllocationRequest {
        private ResourceType resourceType;
        private BigDecimal requiredAmount;
        private LifeEntity requester;
        private Decision decision;
        private String reason;
        private Integer priority = 5;
        private String preferredLocation;
        private List<String> requiredTags;
        private LocalDateTime plannedReleaseAt;
        private boolean startImmediately = true;
        
        // getters and setters
        public ResourceType getResourceType() { return resourceType; }
        public void setResourceType(ResourceType resourceType) { this.resourceType = resourceType; }
        public BigDecimal getRequiredAmount() { return requiredAmount; }
        public void setRequiredAmount(BigDecimal requiredAmount) { this.requiredAmount = requiredAmount; }
        public LifeEntity getRequester() { return requester; }
        public void setRequester(LifeEntity requester) { this.requester = requester; }
        public Decision getDecision() { return decision; }
        public void setDecision(Decision decision) { this.decision = decision; }
        public String getReason() { return reason; }
        public void setReason(String reason) { this.reason = reason; }
        public Integer getPriority() { return priority; }
        public void setPriority(Integer priority) { this.priority = priority; }
        public String getPreferredLocation() { return preferredLocation; }
        public void setPreferredLocation(String preferredLocation) { this.preferredLocation = preferredLocation; }
        public List<String> getRequiredTags() { return requiredTags; }
        public void setRequiredTags(List<String> requiredTags) { this.requiredTags = requiredTags; }
        public LocalDateTime getPlannedReleaseAt() { return plannedReleaseAt; }
        public void setPlannedReleaseAt(LocalDateTime plannedReleaseAt) { this.plannedReleaseAt = plannedReleaseAt; }
        public boolean isStartImmediately() { return startImmediately; }
        public void setStartImmediately(boolean startImmediately) { this.startImmediately = startImmediately; }
    }
    
    public static class ResourceAllocationResult {
        private boolean success;
        private String message;
        private ResourceAllocation allocation;
        
        public static ResourceAllocationResult success(ResourceAllocation allocation) {
            ResourceAllocationResult result = new ResourceAllocationResult();
            result.setSuccess(true);
            result.setAllocation(allocation);
            result.setMessage("资源分配成功");
            return result;
        }
        
        public static ResourceAllocationResult failed(String message) {
            ResourceAllocationResult result = new ResourceAllocationResult();
            result.setSuccess(false);
            result.setMessage(message);
            return result;
        }
        
        // getters and setters
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public ResourceAllocation getAllocation() { return allocation; }
        public void setAllocation(ResourceAllocation allocation) { this.allocation = allocation; }
    }
    
    public static class ResourceOptimizationRequest {
        private OptimizationGoal optimizationGoal;
        private List<ResourceType> targetResourceTypes;
        private BigDecimal maxCostThreshold;
        private BigDecimal minEfficiencyThreshold;
        
        // getters and setters
        public OptimizationGoal getOptimizationGoal() { return optimizationGoal; }
        public void setOptimizationGoal(OptimizationGoal optimizationGoal) { this.optimizationGoal = optimizationGoal; }
        public List<ResourceType> getTargetResourceTypes() { return targetResourceTypes; }
        public void setTargetResourceTypes(List<ResourceType> targetResourceTypes) { this.targetResourceTypes = targetResourceTypes; }
        public BigDecimal getMaxCostThreshold() { return maxCostThreshold; }
        public void setMaxCostThreshold(BigDecimal maxCostThreshold) { this.maxCostThreshold = maxCostThreshold; }
        public BigDecimal getMinEfficiencyThreshold() { return minEfficiencyThreshold; }
        public void setMinEfficiencyThreshold(BigDecimal minEfficiencyThreshold) { this.minEfficiencyThreshold = minEfficiencyThreshold; }
    }
    
    public static class ResourceOptimizationResult {
        private boolean success;
        private String message;
        private OptimizationGoal optimizationGoal;
        private int originalAllocations;
        private int optimizedAllocations;
        private BigDecimal costSavings;
        private BigDecimal performanceImprovement;
        private BigDecimal utilizationImprovement;
        
        // getters and setters
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public OptimizationGoal getOptimizationGoal() { return optimizationGoal; }
        public void setOptimizationGoal(OptimizationGoal optimizationGoal) { this.optimizationGoal = optimizationGoal; }
        public int getOriginalAllocations() { return originalAllocations; }
        public void setOriginalAllocations(int originalAllocations) { this.originalAllocations = originalAllocations; }
        public int getOptimizedAllocations() { return optimizedAllocations; }
        public void setOptimizedAllocations(int optimizedAllocations) { this.optimizedAllocations = optimizedAllocations; }
        public BigDecimal getCostSavings() { return costSavings; }
        public void setCostSavings(BigDecimal costSavings) { this.costSavings = costSavings; }
        public BigDecimal getPerformanceImprovement() { return performanceImprovement; }
        public void setPerformanceImprovement(BigDecimal performanceImprovement) { this.performanceImprovement = performanceImprovement; }
        public BigDecimal getUtilizationImprovement() { return utilizationImprovement; }
        public void setUtilizationImprovement(BigDecimal utilizationImprovement) { this.utilizationImprovement = utilizationImprovement; }
    }
    
    public enum OptimizationGoal {
        COST_OPTIMIZATION,
        PERFORMANCE_OPTIMIZATION,
        UTILIZATION_OPTIMIZATION,
        BALANCED_OPTIMIZATION
    }
}